package org.example.config;

import org.dom4j.DocumentException;
import org.example.dto.SqlData;
import org.example.executor.Executor;
import org.example.executor.impl.ExecutorImpl;
import org.example.session.Session;
import org.example.session.SessionInit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.beans.PropertyVetoException;
import java.io.File;
import java.lang.reflect.*;
import java.util.List;
import java.util.Map;

//@Configuration
public class MapperBeanConfig implements Session {
    Configurations configurations;

    //@Autowired
    private ApplicationContext applicationContext;

    @Override
    public <E> List<E> selectList(SqlData sqlData, Object... params) throws Exception {
        Executor executor = new ExecutorImpl();
        List<Object> query = executor.query(configurations, sqlData, params);
        return (List<E>) query;
    }

    @Override
    public <E> E select(SqlData sqlData, Object... params) throws Exception {
        List<Object> objects = selectList(sqlData, params);
        if (objects == null || objects.size() ==0)
        {
            return null;
        }
        if (objects.size()>1)
        {
            throw new RuntimeException("查到不止一个");
        }

        return (E) objects.get(0);
    }

    @Override
    public <E> E insert(SqlData sqlData, Object... params) throws Exception {
        Executor executor = new ExecutorImpl();
        List<Object> query = executor.query(configurations, sqlData, params);
        return (E) query.get(0);
    }

    @Override
    public <E> E update(SqlData sqlData, Object... params) throws Exception {
        Executor executor = new ExecutorImpl();
        List<Object> query = executor.query(configurations, sqlData, params);
        return (E) query.get(0);
    }

    @Override
    public <E> E delete(SqlData sqlData, Object... params) throws Exception {
        Executor executor = new ExecutorImpl();
        List<Object> query = executor.query(configurations, sqlData, params);
        return (E) query.get(0);
    }

    @Bean
    public void generateBean() throws ClassNotFoundException, PropertyVetoException, DocumentException {
        File fileRoot = new File("src/main/java/org/example/mapper");
        if (!fileRoot.exists())
        {
            System.out.println("文件不存在");
            return;
        }
        File[] files = fileRoot.listFiles((str, name) -> {
            return name.endsWith(".java");
        });
        for (File file : files) {
            String fileName = file.getName().replace(".java","");
            String path = "org.example.mapper." + fileName;
            Class<?> aClass = Class.forName(path);
            Object mapper = getMapper(aClass);
            registerBean(aClass,mapper);
        }
    }

    private void registerBean(Class<?> mapperClass, Object mapperBean) {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();

//        GenericBeanDefinition definition = new GenericBeanDefinition();
//        definition.setBeanClass(mapperClass);
//        definition.setScope(GenericBeanDefinition.SCOPE_SINGLETON);
//
//        beanFactory.registerBeanDefinition(mapperClass.getSimpleName(),definition);
        System.out.println(mapperClass.getSimpleName());
        beanFactory.registerSingleton(mapperClass.getSimpleName(),mapperBean);
    }

    @Override
    public <T> T getMapper(Class<?> mapperType) throws PropertyVetoException, DocumentException {

        if (mapperType == null)
        {
            System.out.println("mapper为空");
            return null;
        }

        ClassLoader classLoader = mapperType.getClassLoader();
        System.out.println(classLoader);
        configurations = SessionInit.init();
        Object instance = Proxy.newProxyInstance(mapperType.getClassLoader(), new Class[]{mapperType}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //这个方法的名字。通过类名和方法名去解析configuration拿到相应的xml文件，然后去调用相应的方法
                String methodName = method.getName();

                //类的名字。那个类下的方法
                String className = method.getDeclaringClass().getName();

                //方法的返回类型
                Type genericReturnType = method.getGenericReturnType();

                Map<String, SqlData> map = configurations.getMap();
                String key = className+"."+ methodName;
                System.out.println("key:"+ key);
                SqlData sqlData = map.get(className + "." + methodName);
//                if (sqlData == null)
//                {
//                    return null;
//                }
                String type = sqlData.getType();
                if ("insert".equals(type))
                {
                    return insert(sqlData,args);
                }else if ("update".equals(type))
                {
                    return update(sqlData,args);
                }
                else if ("delete".equals(type))
                {
                    return delete(sqlData,args);
                }
                String resultType = sqlData.getResultType();
                //参数化类型
                if (genericReturnType instanceof ParameterizedType)
                {
                    return selectList(sqlData,args);
                }else {
                    return select(sqlData,args);
                }
            }
        });
        //System.out.println(instance);
        return (T) instance;
    }
}
